package com.nineclock.signIn.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.enums.MessageTypeEnum;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.excel.excelUtils;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.filter.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.common.utils.DateTimeUtil;
import com.nineclock.signIn.dto.SignInfoDTO;
import com.nineclock.signIn.dto.SignInfoDepartmentDTO;
import com.nineclock.signIn.dto.SignInfoListDTO;
import com.nineclock.signIn.dto.SignInfoRecordDTO;
import com.nineclock.signIn.excel.ExcelMember;
import com.nineclock.signIn.excel.ExcelMemberListener;
import com.nineclock.signIn.mapper.SignInfoMapper;
import com.nineclock.signIn.mapper.SignPictureMapper;
import com.nineclock.signIn.msg.MessageDTO;
import com.nineclock.signIn.pojo.SignInfo;
import com.nineclock.signIn.pojo.SignPicture;
import com.nineclock.signIn.service.SigInService;
import com.nineclock.system.dto.SysCompanyUserDTO;
import com.nineclock.system.feign.SysCompanyUserFeign;
import jdk.nashorn.internal.scripts.JS;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author : Liu
 * @date : 2021/12/1 0001 17:12
 */
@Service
@Transactional
@Slf4j
public class SigInServiceImpl implements SigInService {

    @Autowired
    private SignInfoMapper signInfoMapper;

    @Autowired
    private SignPictureMapper signPictureMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SysCompanyUserFeign companyUserFeign;

    @Autowired
    private excelUtils excel;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Override
    public void SignInAPP(SignInfoDTO signInfoDTO) {
        if (signInfoDTO == null) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        List<String> images = Arrays.asList(signInfoDTO.getImages().split(","));
        Date TimeNow = new Date();
        SimpleDateFormat CreateDate_formatter = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat CreateMonth_formatter = new SimpleDateFormat("yyyy-MM");

        // 插入签到数据
        SignInfo signInfo = BeanHelper.copyProperties(signInfoDTO, SignInfo.class);
        signInfo.setCompanyId(CurrentUserHolder.get().getCompanyId());
        signInfo.setCompanyUserId(CurrentUserHolder.get().getCompanyUserId());
        signInfo.setCreateTime(DateTimeUtil.dateToStr(TimeNow,DateTimeUtil.STANDARD_FORMAT));
        signInfo.setCreateDate(CreateDate_formatter.format(TimeNow));
        signInfo.setCreateMonth(CreateMonth_formatter.format(TimeNow));
        signInfoMapper.insert(signInfo);

        // 插入图片数据
        SignPicture signPicture = new SignPicture();
        for (String image : images) {
            signPicture.setSignId(signInfo.getId());
            signPicture.setUrl(image);
            signPictureMapper.insert(signPicture);
        }

        // 将当月签到次数和当日签到次数更新Redis中, key: SignInMonthAndDay + CompanyId + CompanyUserId  Value: {month: X , day: X}
        Calendar cal = Calendar.getInstance();
        int month = cal.get(Calendar.MONTH) + 1;    //当前月
        int day = cal.get(Calendar.DAY_OF_MONTH);   //当前日
        String key = "SignInMonth" + CurrentUserHolder.get().getCompanyId() + CurrentUserHolder.get().getCompanyUserId() + month + day;
        int dayCount = 0;
        if (Boolean.TRUE.equals(redisTemplate.hasKey(key))) {   //已存在就修改后存入
            dayCount = (int)redisTemplate.opsForValue().get(key);
        }
        redisTemplate.opsForValue().set(key,dayCount+1);;

        //推送消息给当前签到用户，发送消息至MQ，签到服务接收消息
        //调用feign接口查询当前签到用户信息
       SysCompanyUserDTO companyUserDTO = companyUserFeign.queryCompanyUserById(signInfo.getCompanyUserId()).getData();

        // 定义消息内容
        MessageDTO messageDTO = new MessageDTO();
        messageDTO.setMessageType(MessageTypeEnum.ATTEND_NOTIFY.getType());//消息类型
        messageDTO.setCompanyId(signInfo.getCompanyId().toString());//公司id
        messageDTO.setTitle(MessageTypeEnum.ATTEND_NOTIFY.getTitle());//标题
        messageDTO.setContent(companyUserDTO.getUserName()+"签到成功");//内容
        messageDTO.setUseStatus(0);//未读
        messageDTO.setAudience(MessageTypeEnum.ATTEND_NOTIFY.getAudience());//消息作用域

        messageDTO.setTargets(Arrays.asList(companyUserDTO.getMobile()));//目标用户，即签到人

        // 发送消息，参数1-消息的主题:标签，参数2-消息内容（一般用json字符串）
        rocketMQTemplate.convertAndSend("signMessagePushTopic", JSON.toJSONString(messageDTO));
    }

    @Override
    public void export(String startTime, String endTime) throws Exception{
        List<String> dateList = DateTimeUtil.getSpanDateList(startTime, endTime);
        //获取startTime到endTime的员工id
        Long companyId = CurrentUserHolder.get().getCompanyId();
        List<SignInfo> signInfos = signInfoMapper.queryCompanyUserId(companyId, startTime, endTime);
        //获取数据
        ArrayList<SignInfoListDTO> signInfoListDTOS = this.getSignInfoListDTOS(dateList, signInfos);

        excel.export(this.handleHeaders(signInfoListDTOS),this.handleData(signInfoListDTOS));
    }



    @Override
    public int getDayCount() {
        // 将当月签到次数和当日签到次数更新Redis中, key: SignInMonthAndDay + CompanyId + CompanyUserId  Value: {month: X , day: X}
        Calendar cal = Calendar.getInstance();
        int month = cal.get(Calendar.MONTH) + 1;    //当前月
        int day = cal.get(Calendar.DAY_OF_MONTH);   //当前日
        String key = "SignInMonth" + CurrentUserHolder.get().getCompanyId() + CurrentUserHolder.get().getCompanyUserId() + month + day;
        if (!redisTemplate.hasKey(key)) {   //如果不存在
            return 0;
        }
        int count = (int)redisTemplate.opsForValue().get(key);
        return count;
    }



    /**
     * 获取签到列表
     * @param startTime
     * @param endTime
     */
    @Override
    public PageResult<SignInfoListDTO> querySignList(String startTime, String endTime, Long page, Long pageSize) {
        //1). 获取起止日期内(包含起止日期)，所有日期的集合 ;
        List<String> dateList = DateTimeUtil.getSpanDateList(startTime, endTime);

        //查询这段日期内签到过的员工数据
        //创建分页对象
        IPage<SignInfo> ipage = new Page<>(page,pageSize);

        //查询自定义分页数据
        LambdaQueryWrapper<SignInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.between(SignInfo::getCreateDate,startTime,endTime);
        wrapper.eq(SignInfo::getCompanyId,CurrentUserHolder.get().getCompanyId());
        IPage<SignInfo> signInfoIPage = signInfoMapper.selectMyPage(ipage, wrapper);

        //获取签到数据
        List<SignInfo> records = signInfoIPage.getRecords();

        //调用公共方法获取签到数据
        ArrayList<SignInfoListDTO> signInfoListDTOS = getSignInfoListDTOS(dateList, records);

        //封装返回数据
        return new PageResult<>(signInfoIPage.getTotal(),signInfoIPage.getPages(),signInfoListDTOS);
    }

    //公共方法 获取数据
    private ArrayList<SignInfoListDTO> getSignInfoListDTOS(List<String> dateList, List<SignInfo> signInfoList) {
        //创建结果集集合
        ArrayList<SignInfoListDTO> signInfoListDTOS = new ArrayList<>();


        if (!CollectionUtils.isEmpty(signInfoList)){
            //遍历结果集
            for (SignInfo signInfo : signInfoList) {

                //创建返回数据模型
                SignInfoListDTO infoListDTO = new SignInfoListDTO();

                //根据员工id查询员工数据
                SysCompanyUserDTO companyUserDTO = companyUserFeign.queryCompanyUserById(signInfo.getCompanyUserId()).getData();

                if (companyUserDTO!=null){
                    //设置员工基本信息
                    infoListDTO.setId(companyUserDTO.getId());
                    infoListDTO.setUsername(companyUserDTO.getUserName());
                    infoListDTO.setWorkNumber(companyUserDTO.getWorkNumber());
                    infoListDTO.setPost(companyUserDTO.getPost());

                    //设置部门数据
                    SignInfoDepartmentDTO departmentDTO = new SignInfoDepartmentDTO();
                    departmentDTO.setId(companyUserDTO.getDepartmentId());
                    departmentDTO.setName(companyUserDTO.getDepartmentName());
                    infoListDTO.setDepartment(departmentDTO);

                    //创建签到数据集合
                    List<SignInfoRecordDTO> signInfoRecordDTOS = new ArrayList<>();

                    //遍历日期区间，设置签到情况
                    for (String data : dateList) {
                        //获取日期中的月份和日
                        String[] date = data.split("-");
                        String month = date[1].replaceFirst("^0*", "");
                        String day = date[2].replaceFirst("^0*", "");

                        //获取当前员工的签到key
                        //SignInMonth,公司id，用户id，月，日
                        //例子:SignInMonth11122
                        //拼接key
                        String key = "SignInMonth" + companyUserDTO.getCompanyId() + signInfo.getCompanyUserId() + month +day;

                        //定义签到次数
                        Long SignCount = 0L;
                        //判断redis是否存在该用户的这个日期的签到数据
                        if (Boolean.TRUE.equals(redisTemplate.hasKey(key))) {
                            int count = (int) redisTemplate.opsForValue().get(key);
                            SignCount = Long.valueOf(count);
                        }

                        //创建签到数据模型
                        SignInfoRecordDTO infoRecordDTO = new SignInfoRecordDTO();
                        //设置数据
                        infoRecordDTO.setSignDate(data);
                        infoRecordDTO.setSignCount(SignCount);

                        //添加到签到数据集合
                        signInfoRecordDTOS.add(infoRecordDTO);

                        //设置签到数据
                        infoListDTO.setSigns(signInfoRecordDTOS);
                    }
                    //添加到方法返回结果集
                    signInfoListDTOS.add(infoListDTO);
                }
            }

        }
        //返回数据
        return signInfoListDTOS;
    }

    //APP: 查询本月签到记录
    @Override
    public List<SignInfoDTO> pagingSignCurrentUserByMonth() {
        //获取当前月份
        Date now = new Date();
        String monthDate = DateTimeUtil.dateToStr(now, DateTimeUtil.TIME_FORMAT_4);

        //获取当前员工id和企业id
        Long companyId = CurrentUserHolder.get().getCompanyId();
        Long companyUserId = CurrentUserHolder.get().getCompanyUserId();

        //构造查询条件
        LambdaQueryWrapper<SignInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SignInfo::getCompanyId,companyId);
        wrapper.eq(SignInfo::getCompanyUserId,companyUserId);
        wrapper.eq(SignInfo::getCreateMonth,monthDate);

        List<SignInfo> signInfoList = signInfoMapper.selectList(wrapper);

        if (!CollectionUtils.isEmpty(signInfoList)){
            List<SignInfoDTO> signInfoDTOList = signInfoList.stream().map(signInfo -> {

                SignInfoDTO signInfoDTO = BeanHelper.copyProperties(signInfo, SignInfoDTO.class);
//              //签到时间
                String createTime = signInfo.getCreateTime();
                if(createTime != null && createTime.length()>19){
                    createTime= createTime.substring(0,19);
                }
                String createTimeToStr = DateTimeUtil.dateToStr(DateTimeUtil.strToDate(createTime),DateTimeUtil.STANDARD_FORMAT);

//
                signInfoDTO.setCreateTime(createTimeToStr);
                //根据签到表id 查询图片地址
                LambdaQueryWrapper<SignPicture> pictureWrapper = new LambdaQueryWrapper<>();
                pictureWrapper.eq(SignPicture::getSignId, signInfoDTO.getId());

                List<SignPicture> signPictureList = signPictureMapper.selectList(pictureWrapper);
                if (!CollectionUtils.isEmpty(signPictureList)) {

                    //设置图片地址
                    List<String> urlList = signPictureList.stream().map(signPicture -> {
                        return signPicture.getUrl();
                    }).collect(Collectors.toList());

                    signInfoDTO.setSignPictureUrlList(urlList);
                }

                return signInfoDTO;
            }).collect(Collectors.toList());

            return signInfoDTOList;
        }


        return null;
    }

    /**
     * 动态构造表头
     * @param signInfoListDTOS
     * @return
     */
    private List<List<String>> handleHeaders(List<SignInfoListDTO> signInfoListDTOS) {
        List<List<String>> headers = new ArrayList<>();

        headers.add(Arrays.asList("姓名"));
        headers.add(Arrays.asList("工号"));
        headers.add(Arrays.asList("部门"));
        headers.add(Arrays.asList("职位"));

        if(!CollectionUtils.isEmpty(signInfoListDTOS)){

            SignInfoListDTO signInfoListDTO =signInfoListDTOS.get(0);
            List<SignInfoRecordDTO> signList = signInfoListDTO.getSigns();


            if(!CollectionUtils.isEmpty(signList)){

                for (SignInfoRecordDTO signInfoRecordDTO : signList) {
                    headers.add(Arrays.asList(signInfoRecordDTO.getSignDate()));
                }
            }

        }
        return headers;
    }

    /**
     * 动态构造每一行数据
     * @param signInfoListDTOS
     * @return
     */
    private List<List<String>> handleData(List<SignInfoListDTO> signInfoListDTOS) {
        List<List<String>> dataList = new ArrayList<>();

        if(!CollectionUtils.isEmpty(signInfoListDTOS)){

            // 遍历每一行数据
            for (SignInfoListDTO signInfoListDTO : signInfoListDTOS) {
                List<String> row = new ArrayList<>();

                row.add(signInfoListDTO.getUsername());
                row.add(signInfoListDTO.getWorkNumber());
                row.add(signInfoListDTO.getDepartment().getName());
                row.add(signInfoListDTO.getPost());

                List<SignInfoRecordDTO> signs = signInfoListDTO.getSigns();
                if (!CollectionUtils.isEmpty(signs)){

                    for (SignInfoRecordDTO sign : signs) {
                        row.add(sign.getSignCount().toString());
                    }
                }
                dataList.add(row);
            }
        }
        return dataList;
    }

    //PC: 导入签到列表
    @Override
    public void importList(MultipartFile multipartFile) throws Exception {

        if (multipartFile == null){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
//        File file = new File("D:\\测试文件.xls");


        // 解析数据
//        EasyExcel.read(excelFile.getInputStream(), ExcelMember.class,
//                new ExcelMemberListener(this)).sheet(0).doRead();
        EasyExcel.read(multipartFile.getInputStream(),ExcelMember.class,new ExcelMemberListener(this)).sheet(0).doRead();

    }


    //写入数据库
    @Override
    public void saveSignIn(List<ExcelMember> memberList) {

        if (CollectionUtils.isEmpty(memberList)){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        //转换数据 创建集合存放签到数据
//        List<SignInfo> signInfoList = new ArrayList<>();
        for (ExcelMember excelMember : memberList) {

            //根据员工电话查询员工信息
            SysCompanyUserDTO companyUserDTO = companyUserFeign.findCompanyUserByMobile(excelMember.getMobile()).getData();
            if (companyUserDTO != null){
                SignInfo signInfo = BeanHelper.copyProperties(excelMember, SignInfo.class);
                signInfo.setCompanyId(companyUserDTO.getCompanyId());
                signInfo.setCompanyUserId(companyUserDTO.getId());

                //设置签到日期和签到月份
                String createTime = signInfo.getCreateTime();



                String createDate = createTime.substring(0, 10);
                System.out.println("签到日期: "+createDate);

                String createMonth = createTime.substring(0, 7);
                System.out.println("签到月份: "+createMonth);

                signInfo.setCreateDate(createDate);
                signInfo.setCreateMonth(createMonth);

                signInfoMapper.insert(signInfo);

                // 将当月签到次数和当日签到次数更新Redis中, key: SignInMonthAndDay + CompanyId + CompanyUserId  Value: {month: X , day: X}
                String[] DateList1 = createTime.split(" ");
                String[] DateList = DateList1[0].split("-");
                Long id = companyUserDTO.getId();
                System.out.println("id = " + id);
                String key = "SignInMonth" + CurrentUserHolder.get().getCompanyId() + id + Integer.parseInt(DateList[1]) + Integer.parseInt(DateList[2]);
                System.out.println(key);
                int dayCount = 0;
                if (Boolean.TRUE.equals(redisTemplate.hasKey(key))) {   //已存在就修改后存入
                    dayCount = (int)redisTemplate.opsForValue().get(key);
                }
                redisTemplate.opsForValue().set(key,dayCount+1);;
//            signInfoList.add(signInfo);
            }

        }
    }
}
